<template>
  <div id="app">
    <div class="container">
      <!-- 创建一个canvas画布 npmn-js是通过canvas实现绘图的，并设置ref让vue获取到element -->
      <div class="bpmn-canvas" ref="canvas"></div>
      <!-- 工具栏显示的地方 -->
      <div class="bpmn-js-properties-panel" id="js-properties-panel"></div>
      <!-- 把操作按钮写在这里面 -->
      <div class="action">
        <el-upload action class="upload-demo" :before-upload="openBpmn">
          <el-button icon="el-icon-folder-opened"></el-button>
        </el-upload>
        <el-button class="new" icon="el-icon-circle-plus" @click="newDiagram"></el-button>
        <el-button icon="el-icon-download" @click="downloadBpmn"></el-button>
        <el-button icon="el-icon-picture" @click="downloadSvg"></el-button>
        <a hidden ref="downloadLink"></a>
      </div>
    </div>
    <!--让用户选择-->
    <!--    <el-dialog title="提示" :visible.sync="nodeVisible" width="30%" :before-close="handleClose">-->
    <!--      <el-form ref="form" :model="form" label-width="80px">-->
    <!--        <el-form-item label="选择用户">-->
    <!--          <el-select v-model="form.name" placeholder="请选择">-->
    <!--            <el-option-->
    <!--              v-for="item in options"-->
    <!--              :key="item.value"-->
    <!--              :label="item.label"-->
    <!--              :value="item.label"-->
    <!--            ></el-option>-->
    <!--          </el-select>-->
    <!--        </el-form-item>-->
    <!--      </el-form>-->
    <!--      <span slot="footer" class="dialog-footer">-->
    <!--        <el-button @click="$store.commit('TOGGLENODEVISIBLE', false)">取 消</el-button>-->
    <!--        <el-button type="primary" @click="confirm">确 定</el-button>-->
    <!--      </span>-->
    <!--    </el-dialog>-->
  </div>
</template>

<script>
// 完全自定义
// import CustomModeler from './customModeler'

// bpmn
import BpmnModeler from 'bpmn-js/lib/Modeler'
// 静态字符串 后面要换成服务器的
import { xmlStr } from './mock-data/xmlStr'
// 工具栏相关
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
import propertiesPanelModule from 'bpmn-js-properties-panel'
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'
//  翻译模块
import customTranslate from '@/flow-chart/language/customTranslate/customTranslate'
// 自定义
import customModule from '@/flow-chart/custom/index'
// 状态
import { mapState } from 'vuex'
// vue仓库
import store from '@/store/index'

export default {
  data () {
    return {
      bpmnModeler: null,
      canvas: null,
      bpmnTemplate: xmlStr,
      // dialogVisible: false,
      // 表单绑定对象
      form: {
        name: ''
      },
      // 当前最新的数据
      xml: '',
      // 事件对象
      e: {},
      // 假装是后台的数据
      options: [
        {
          value: '选项1',
          label: '黄金糕'
        },
        {
          value: '选项2',
          label: '双皮奶'
        },
        {
          value: '选项3',
          label: '蚵仔煎'
        },
        {
          value: '选项4',
          label: '龙须面'
        },
        {
          value: '选项5',
          label: '北京烤鸭'
        }
      ]
    }
  },
  mounted () {
    this.init()
  },
  computed: {
    ...mapState({
      // nodeVisible: (state) => state.flowchart.nodeVisible
    })
  },
  methods: {
    // 初始化 bpmn
    async init () {
      // 替换语言模块
      const customTranslateModule = {
        translate: ['value', customTranslate]
      }
      // 获取画布 element
      this.canvas = this.$refs.canvas
      // 创建Bpmn对象
      this.bpmnModeler = new BpmnModeler({
        // this.bpmnModeler = new CustomModeler({ // 完全自定义打开这个
        // 设置bpmn的绘图容器为上门获取的画布 element
        container: this.canvas,
        // 加入右侧工具栏支持
        /**
         * propertiesProviderModule 右侧工具栏
         * propertiesPanelModule 右侧工具栏
         * customTranslateModule 替换语言
         * customModule 自定义模块
         */
        propertiesPanel: {
          parent: '#js-properties-panel'
        },
        additionalModules: [
          propertiesProviderModule,
          propertiesPanelModule,
          customTranslateModule,
          customModule
        ],
        moddleExtensions: {
          camunda: camundaModdleDescriptor
        }
      })
      await this.createNewDiagram(this.bpmnTemplate)
    },
    // 新建操作
    newDiagram () {
      this.createNewDiagram(this.bpmnTemplate)
    },
    // 点击了下载按钮
    downloadBpmn () {
      this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
        if (!err) {
          // 获取文件名
          const name = `${this.getFilename(xml)}.bpmn`
          // 将文件名以及数据交给下载方法
          this.download({
            name: name,
            data: xml
          })
        }
      })
    },
    // 点击了以svg格式下载
    downloadSvg () {
      this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
        if (!err) {
          // 获取文件名
          const name = `${this.getFilename(xml)}.svg`

          // 从建模器画布中提取svg图形标签
          let context = ''
          const djsGroupAll = this.$refs.canvas.querySelectorAll('.djs-group')
          for (const item of djsGroupAll) {
            context += item.innerHTML
          }
          // 获取svg的基本数据，长宽高
          const viewport = this.$refs.canvas
            .querySelector('.viewport')
            .getBBox()
          // 将标签和数据拼接成一个完整正常的svg图形
          const svg = `
            <svg
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              width="${viewport.width}"
              height="${viewport.height}"
              viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
              version="1.1"
              >
              ${context}
            </svg>
          `
          // 将文件名以及数据交给下载方法
          this.download({
            name: name,
            data: svg
          })
        }
      })
    },
    // 打开 bpmn
    openBpmn (file) {
      const reader = new FileReader()
      // 读取File对象中的文本信息，编码格式为UTF-8
      reader.readAsText(file, 'utf-8')
      reader.onload = () => {
        // 读取完毕后将文本信息导入到Bpmn建模器
        this.createNewDiagram(reader.result)
      }
      return false
    },
    // 获取文件名
    getFilename (xml) {
      const start = xml.indexOf('process')
      let filename = xml.substr(start, xml.indexOf('>'))
      filename = filename.substr(filename.indexOf('id') + 4)
      filename = filename.substr(0, filename.indexOf('"'))
      return filename
    },
    // 下载文件的方法
    download ({
      name = 'diagram.bpmn',
      data
    }) {
      // 这里就获取到了之前设置的隐藏链接
      const downloadLink = this.$refs.downloadLink
      // 把输就转换为URI，下载要用到的
      const encodedData = encodeURIComponent(data)
      if (data) {
        // 将数据给到链接
        downloadLink.href =
            'data:application/bpmn20-xml;charset=UTF-8,' + encodedData
        // 设置文件名
        downloadLink.download = name
        // 触发点击事件开始下载
        downloadLink.click()
      }
    },
    // 创建一个新的图
    async createNewDiagram (bpmn) {
      // 将字符串转换成图显示出来
      this.bpmnModeler.importXML(bpmn, (err) => {
        if (err) {
          this.$Message.error('打开模型出错,请确认该模型符合Bpmn2.0规范')
        } else {
          this.success()
        }
      })
    },
    success () {
      console.log('创建成功!')
      // 添加事件的方法
      this.addBpmnListener() // 添加一个xml发生变化的时候触发的事件
      this.addEventBusListener() // 添加一个用户点击element的时候的事件
    },
    // 添加一个xml发生变化的时候触发的事件
    addBpmnListener () {
      const that = this
      // 给图绑定事件，当图有发生改变就会触发这个事件
      this.bpmnModeler.on('commandStack.changed', () => {
        // eslint-disable-next-line handle-callback-err
        that.saveDiagram((err, xml) => {
          that.xml = xml
          console.log(that.xml) // 这里获取到的就是最新的xml信息
        })
      })
    },
    // 下载为bpmn格式,done是个函数，调用的时候传入的
    saveDiagram (done) {
      // 把传入的done再传给bpmn原型的saveXML函数调用
      this.bpmnModeler.saveXML({ format: true }, function (err, xml) {
        done(err, xml)
      })
    },
    // 添加一个用户点击element的时候的事件
    addEventBusListener () {
      const that = this
      const eventBus = this.bpmnModeler.get('eventBus')
      // const modeling = this.bpmnModeler.get('modeling')
      // const elementRegistry = this.bpmnModeler.get('elementRegistry')
      const eventTypes = ['element.click', 'element.changed']
      eventTypes.forEach(function (eventType) {
        eventBus.on(eventType, function (e) {
          if (!e || e.element.type === 'bpmn:Process') return // type: "bpmn:Process" 排除点击画布
          if (!e || !e.element) {
            console.log('无效的e', e)
            return
          }
          if (eventType === 'element.click') {
            // 点击的是元素 doing...
            // store.commit("TOGGLENODEVISIBLE", true)
            that.e = e
            console.log('点击了element', e)
          }
        })
      })
    },
    // 弹出框点击了确认
    confirm () {
      this.edit()
    },
    // 确定修改
    edit () {
      // const that = this
      const modeling = this.bpmnModeler.get('modeling')
      const elementRegistry = this.bpmnModeler.get('elementRegistry')
      const shape = this.e.element
        ? elementRegistry.get(this.e.element.id)
        : this.e.shape
      console.log(shape)
      modeling.updateProperties(shape, {
        name: this.form.name
      })
      this.$refs.form.resetFields()
      this.form.name = ''
      store.commit('TOGGLENODEVISIBLE', false)
    },
    // 对话框被关闭了
    handleClose () {
    }
  }
}
</script>

<style scoped lang="less">
@import "./style/app.css";

.bpmn-canvas {
  width: 100%;
  height: 100vh;
}

.action {
  position: fixed;
  bottom: 10px;
  left: 10px;
  display: flex;
}

.upload-demo {
  margin-right: 10px;
}

// 右侧工具栏
.bpmn-js-properties-panel {
  position: absolute;
  top: 0;
  right: 0;
  width: 300px;
}
</style>
